<template>
  <div :style="styles">
    <div class="xs-container">
      <slot></slot>
      <slot name="pulldown"></slot>
      <slot name="pullup"></slot>
    </div>
  </div>
</template>

<script>
import objectAssign from 'object-assign'
import XScroll from 'vux-xscroll/build/cmd/xscroll.js'
import Pulldown from 'vux-xscroll/build/cmd/plugins/pulldown'
import Pullup from 'vux-xscroll/build/cmd/plugins/pullup'

const pulldownDefaultConfig = () => ({
  content: 'Pull Down To Refresh',
  height: 60,
  autoRefresh: false,
  downContent: 'Pull Down To Refresh',
  upContent: 'Release To Refresh',
  loadingContent: 'Loading...',
  clsPrefix: 'xs-plugin-pulldown-',
})

const pullupDefaultConfig = () => ({
  content: 'Pull Up To Refresh',
  pullUpHeight: 60,
  height: 40,
  autoRefresh: false,
  downContent: 'Release To Refresh',
  upContent: 'Pull Up To Refresh',
  loadingContent: 'Loading...',
  clsPrefix: 'xs-plugin-pullup-',
})
var vendor = (function vendor() {
  var el = document.createElement('div').style
  var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'],
    transform,
    i = 0,
    l = vendors.length
  for (; i < l; i++) {
    transform = vendors[i] + 'ransform'
    if (transform in el) return vendors[i].substr(0, vendors[i].length - 1)
  }
  return false
})()
function prefixStyle(attrName) {
  if (vendor === false) return false
  if (vendor === '') return attrName
  return vendor + attrName.charAt(0).toUpperCase() + attrName.substr(1)
}
var transform = prefixStyle('transform')
export default {
  name: 'scroller',
  props: {
    value: {
      type: Object,
      default: () => {
        return {
          pulldownStatus: '',
          pullupStatus: '',
        }
      },
    },
    height: String,
    lockX: Boolean,
    lockY: Boolean,
    scrollbarX: Boolean,
    scrollbarY: Boolean,
    bounce: {
      type: Boolean,
      default: true,
    },
    useOriginScroll: {
      type: Boolean,
      default: false,
    },
    useTransition: {
      type: Boolean,
      default: true,
    },
    preventDefault: {
      type: Boolean,
      default: false,
    },
    stopPropagation: Boolean,
    boundryCheck: {
      type: Boolean,
      default: true,
    },
    gpuAcceleration: {
      type: Boolean,
      default: true,
    },
    usePulldown: {
      type: Boolean,
      default: false,
    },
    usePullup: {
      type: Boolean,
      default: false,
    },
    /**
     * refer to: http://xscroll.github.io/node_modules/xscroll/doc/PullDown.html
     */
    pulldownConfig: {
      type: Object,
      default() {
        return {}
      },
    },
    pullupConfig: {
      type: Object,
      default() {
        return {}
      },
    },
    enableHorizontalSwiping: {
      type: Boolean,
      default: false,
    },
    scrollBottomOffset: {
      type: Number,
      default: 0,
    },
  },
  methods: {
    reset(scrollPosition, duration, easing) {
      if (scrollPosition) {
        if (typeof scrollPosition.left !== 'undefined') {
          this._xscroll.scrollLeft(scrollPosition.left, duration, easing)
        }
        if (typeof scrollPosition.top !== 'undefined') {
          this._xscroll.scrollTop(scrollPosition.top, duration, easing)
        }
      }
      this._xscroll && this._xscroll.resetSize()
    },
    donePulldown() {
      this.pulldown.reset(() => {
        // repaint
        this.reset()
      })
      this.currentValue.pulldownStatus = 'default'
    },
    disablePullup() {
      // this._xscroll.unplug(this.pullup)
      this.pullup.stop()
      this.currentValue.pullupStatus = 'disabled'
    },
    enablePullup() {
      this.currentValue.pullupStatus = 'default'
      this.pullup.restart()
    },
    donePullup() {
      this.pullup.complete()
      this.reset()
      this.currentValue.pullupStatus = 'default'
    },
    getStyles() {
      let height = this.height
      if (!this.height && this.$el && !this.$el.style.height && this.lockX) {
        height = `${document.documentElement.clientHeight}px`
        this.reset()
      }

      if (this.height && this.height.indexOf('-') === 0) {
        height = `${document.documentElement.clientHeight + parseInt(this.height)}px`
      }
      this.styles = {
        height: `${height}`,
      }
    },
  },
  created() {
    if (!this.value) {
      this.currentValue = {
        pulldownStatus: '',
        pullupStatus: '',
      }
    } else {
      this.currentValue = this.value
    }
    this.handleOrientationchange = () => {
      setTimeout(() => {
        this.reset()
      }, 100)
    }
  },
  data() {
    return {
      currentValue: {},
      styles: {},
    }
  },
  watch: {
    currentValue: {
      handler: function(val) {
        this.$emit('input', pure(val))
      },
      deep: true,
    },
    height() {
      this.getStyles()
    },
    value: {
      handler: function(val) {
        if (val.pullupStatus === 'default' && this.currentValue.pullupStatus !== 'default') {
          this.donePullup()
        }
        if (val.pulldownStatus === 'default' && this.currentValue.pulldownStatus !== 'default') {
          this.donePulldown()
        }
        if (val.pullupStatus === 'disabled' && this.currentValue.pullupStatus !== 'disabled') {
          this.disablePullup()
        }
        if (val.pullupStatus === 'enabled' && this.currentValue.pullupStatus === 'disabled') {
          this.enablePullup()
        }
      },
      deep: true,
    },
  },
  mounted() {
    this.uuid = Math.random()
      .toString(36)
      .substring(3, 8)
    this.$nextTick(() => {
      this.$el.setAttribute('id', `vux-scroller-${this.uuid}`)
      let content = null
      if (this.$slots.default) {
        content = this.$slots.default[0].elm
      }
      if (!content) {
        throw new Error('no content is found')
      }

      this._xscroll = new XScroll({
        renderTo: `#vux-scroller-${this.uuid}`,
        lockX: this.lockX,
        lockY: this.lockY,
        scrollbarX: this.scrollbarX,
        scrollbarY: this.scrollbarY,
        content: content,
        bounce: this.bounce,
        useOriginScroll: this.useOriginScroll,
        useTransition: this.useTransition,
        preventDefault: this.preventDefault,
        boundryCheck: this.boundryCheck,
        gpuAcceleration: this.gpuAcceleration,
        stopPropagation: this.stopPropagation,
      })
      this._xscroll.getScrollTop = () => {
        var transY = window.getComputedStyle(this._xscroll.container)[transform].match(/[-\d\.*\d*e\-\d]+/g)
        return transY ? (Math.round(transY[5]) === 0 ? 0 : -Math.round(transY[5])) : 0
      }

      this._xscroll.on('scroll', () => {
        if (this._xscroll) {
          const top = this._xscroll.getScrollTop()
          this.$emit('on-scroll', {
            top: top,
            left: this._xscroll.getScrollLeft(),
          })
          const containerHeight = this._xscroll.containerHeight
          const scrollHeight = this._xscroll.height
          if (top >= containerHeight - scrollHeight - this.scrollBottomOffset) {
            this.$emit('on-scroll-bottom')
          }
        }
      })

      if (this.usePulldown) {
        // if use slot=pulldown
        let container = this.$slots.pulldown
        let config = objectAssign(pulldownDefaultConfig(), this.pulldownConfig)
        if (container) {
          config.container = container[0].elm
        }
        this.pulldown = new Pulldown(config)
        this._xscroll.plug(this.pulldown)
        this.pulldown.on('loading', (e) => {
          this.$emit('on-pulldown-loading', this.uuid)
        })
        this.pulldown.on('statuschange', (val) => {
          this.currentValue.pulldownStatus = val.newVal
        })
      }

      if (this.usePullup) {
        // if use slot=pullup
        let container = this.$slots.pullup
        let config = objectAssign(pullupDefaultConfig(), this.pullupConfig)

        if (container) {
          config.container = container[0].elm
        }
        this.pullup = new Pullup(config)
        this._xscroll.plug(this.pullup)
        this.pullup.on('loading', (e) => {
          this.$emit('on-pullup-loading', this.uuid)
        })
        this.pullup.on('statuschange', (val) => {
          this.currentValue.pullupStatus = val.newVal
        })
      }

      if (this.enableHorizontalSwiping) {
        this._xscroll.on('panstart', (e) => {
          if (e.direction === 2 || e.direction === 4) {
            e.preventDefault()
            if (this.scrollbarY) {
              this._xscroll.userConfig.scrollbarY = false
            }
            this._xscroll.userConfig.lockY = true
          }
        })
        this._xscroll.on('panend', () => {
          if (this.scrollbarY) {
            this._xscroll.userConfig.scrollbarY = true
          }
          this._xscroll.userConfig.lockY = false
        })
      }

      this._xscroll.render()
      window.addEventListener('orientationchange', this.handleOrientationchange, false)
    })
    this.getStyles()
  },
  updated() {
    this.reset()
  },
  destroyed() {
    if (this.pullup) {
      this._xscroll.unplug(this.pullup)
      this.pullup.pluginDestructor()
    }
    if (this.pulldown) {
      this._xscroll.unplug(this.pulldown)
      this.pulldown.pluginDestructor()
    }
    window.removeEventListener('orientationchange', this.handleOrientationchange, false)
    this._xscroll.destroy()
    this._xscroll = null
  },
}

function pure(obj) {
  return JSON.parse(JSON.stringify(obj))
}
</script>

<style>
.xs-plugin-pullup-container {
  text-align: center;
}
</style>
